/*
    QRoundProgressBar - a circular progress bar Qt widget.
 
    Sintegrial Technologies (c) 2015-now
    Copyright (C) 2023 KylinSoft Co., Ltd.
 
    The software is freeware and is distributed "as is" with the complete source codes.
    Anybody is free to use it in any software projects, either commercial or non-commercial.
    Please do not remove this copyright message and remain the name of the author unchanged.
 
    It is very appreciated if you produce some feedback to us case you are going to use
    the software.
 
    Please send your questions, suggestions, and information about found issues to the
 
    sintegrial@gmail.com
 
*/

#include "qroundProgressBar.h"

#include <QtGui/QPainter>
#include <QtGui/QPainterPath>
#include <QDebug>
#include <QStyleOption>
//#include <QGSettings>


QRoundProgressBar::QRoundProgressBar(QWidget *parent) :
    QWidget(parent),
    m_min(0), m_max(100),
    m_value(25),
    m_nullPosition(PositionTop),
    m_barStyle(StyleDonut),
    m_outlinePenWidth(0.96),
    m_dataPenWidth(1),
    m_rebuildBrush(false),
    m_format("%p%"),
    m_decimals(1),
    m_updateFlags(UF_PERCENT)
{
    settingsStyle();
}

void QRoundProgressBar::setRange(double min, double max)
{
    m_min = min;
    m_max = max;

    if (m_max < m_min)
        qSwap(m_max, m_min);

    if (m_value < m_min)
        m_value = m_min;
    else if (m_value > m_max)
        m_value = m_max;

    if (!m_gradientData.isEmpty())
        m_rebuildBrush = true;

    update();
}

void QRoundProgressBar::setMinimum(double min)
{
    setRange(min, m_max);
}

void QRoundProgressBar::setMaximum(double max)
{
    setRange(m_min, max);
}

void QRoundProgressBar::setValue(double val)
{
    if (m_value != val) {
        if (val < m_min)
            m_value = m_min;
        else if (val > m_max)
            m_value = m_max;
        else
            m_value = val;
        update();
    }
}

//定义最小值位置
void QRoundProgressBar::setNullPosition(double position)
{
    if (position != m_nullPosition) {
        m_nullPosition = position;
        if (!m_gradientData.isEmpty())
            m_rebuildBrush = true;
        update();
    }
}
//设置视觉样式圆环（甜甜圈）风格、饼（派）风格、线型
void QRoundProgressBar::setBarStyle(QRoundProgressBar::BarStyle style)
{
    if (style != m_barStyle) {
        m_barStyle = style;
        update();
    }
}
//设置轮廓圆笔的宽度。
void QRoundProgressBar::setOutlinePenWidth(double penWidth)
{
    if (penWidth != m_outlinePenWidth) {
        m_outlinePenWidth = penWidth;
        update();
    }
}
//设置数据圆笔的宽度。
void QRoundProgressBar::setDataPenWidth(double penWidth)
{
    if (penWidth != m_dataPenWidth) {
        m_dataPenWidth = penWidth;
        update();
    }
}
//设置可见数据的颜色，并使用它们制作渐变画笔。
//此函数将覆盖widget的`palette（）`来设置动态创建的渐变笔刷
void QRoundProgressBar::setDataColors(const QGradientStops &stopPoints)
{
    if (stopPoints != m_gradientData) {
        m_gradientData = stopPoints;
        m_rebuildBrush = true;
        update();
    }
}
//定义用于生成当前文本的字符串。
//％p-用完成的百分比代替。 ％v-由当前值替换。 ％m-由最大值代替。
//默认值为“％p％”
void QRoundProgressBar::setFormat(const QString &format)
{
    if (format != m_format) {
        m_format = format;

        valueFormatChanged();
    }
}
//将格式字符串设置为空字符串。 因此，将不会显示任何文本。
void QRoundProgressBar::resetFormat()
{
    m_format = QString::null;
    valueFormatChanged();
}
//设置要在逗号后显示的小数位数（默认为1）。
void QRoundProgressBar::setDecimals(int count)
{
    if (count >= 0 && count != m_decimals) {
        m_decimals = count;
        valueFormatChanged();
    }
}

void QRoundProgressBar::paintEvent(QPaintEvent* /*event*/)
{
    //构造和自定义（例如，设置笔或画笔）painter。 然后画。 记住在绘制后销毁QPainter对象。
    QPainter painter(this);
    painter.save();
    //mainColor 在settingsStyle配置
    painter.setPen(mainColor);
    painter.setBrush(mainColor);
    //在指定的boundingRectangle中创建一个椭圆，并将其作为封闭的子路径添加到painter路径。
    QPainterPath bigCircle;
    int px = 0;
    int py = 0;
    int ra = 266;
    bool onTablet = GsettingSubject::getInstance()->getOnTablet();
    if(onTablet){
        px = 147;
        py = 147;
        ra = 560;
    }else{
        px = 0;
        py = 0;
        ra = 266;
    }
    bigCircle.addEllipse(65, 13, ra, ra);
    QPainterPath path = bigCircle ;
    painter.drawPath(path);
    //保存当前的画家状态（将状态推送到堆栈上）。 在save（）之后必须有一个相应的restore（）； end（）函数展开堆栈。
    painter.restore();

    double outerRadius = ra/2;
    QRectF baseRect(198+px - outerRadius, 146+py - outerRadius, outerRadius * 2, outerRadius * 2);
    QPainter p(this);
    //表示引擎应尽可能对图元的边缘进行抗锯齿。
    p.setRenderHint(QPainter::Antialiasing);
    // data brush
    rebuildDataBrushIfNeeded();
    // background
    drawBackground(p, rect());
    double innerRadius = ra/2;
    QRectF innerRect = QRectF((198+px - outerRadius) + 5, (146+py - outerRadius) + 5, (outerRadius - 5) * 2 , (outerRadius - 5) * 2 );
    //calculateInnerRect(baseRect, outerRadius, innerRect, innerRadius);
    double arcStep = 360.0 / (m_max - m_min) * m_value;
    // base circle
    drawBase(p, baseRect,innerRect);
    // data circle
    drawValue(p, baseRect, m_value, arcStep,innerRect, innerRadius);
    // finally draw the bar
    p.end();
}

//背景色
void QRoundProgressBar::drawBackground(QPainter &p, const QRectF &baseRect)
{
    p.fillRect(baseRect, palette().background());
}

//画基础
void QRoundProgressBar::drawBase(QPainter &p, const QRectF &baseRect,const QRectF &innerRect)
{

    QStyleOption opt;
    opt.init(this);
    switch (m_barStyle)
    {
    case StyleDonut:
//        p.setPen(QPen(QColor(160, 160, 160), 4, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
//        p.setBrush(Qt::NoBrush);
//        p.drawEllipse(QPointF(227, 180),155,155);
        break;
    case StylePie:
        p.setPen(QPen(palette().base().color(), m_outlinePenWidth, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
        p.setBrush(palette().base());
        p.drawEllipse(baseRect);
        break;
    case StyleLine:
        p.setPen(QPen(palette().base().color(), m_outlinePenWidth ,Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
        p.setBrush(Qt::NoBrush);
        p.drawEllipse(baseRect.adjusted(m_outlinePenWidth/2, m_outlinePenWidth/2, -m_outlinePenWidth/2, -m_outlinePenWidth/2));
        break;
    default:;
    }
}
//画数据
void QRoundProgressBar::drawValue(QPainter &p
                                  , const QRectF &baseRect
                                  , double value
                                  , double arcLength
                                  , const QRectF & innerRect
                                  , double innerRadius)
{
    // nothing to draw
    if (value == m_min)
        return;

    // for Pie and Donut styles
    QPainterPath dataPath;
    dataPath.setFillRule(Qt::WindingFill);
    dataPath.moveTo(baseRect.center());
    dataPath.arcTo(baseRect, m_nullPosition, -arcLength);//大家都是先绘制外圆的弧长

    if(m_barStyle == StyleDonut) {
        // draw dount outer
        QPointF currentPoint = dataPath.currentPosition();//绘制完外圆弧长后，获取绘制完的位置绘制一个直线到达内圆
        currentPoint = baseRect.center() + (currentPoint - baseRect.center()) * m_innerOuterRate;//计算内圆的坐标点，m_innerOuterRate替代了原作者写的0.75，代表内圆是外圆的0.75倍
        dataPath.lineTo(currentPoint);//绘制外圆到内圆的直线
        dataPath.moveTo(baseRect.center());//坐标点回到中心准备绘制内圆弧形
        dataPath.arcTo(innerRect, m_nullPosition-arcLength, arcLength);//绘制内圆的弧形
        currentPoint = dataPath.currentPosition();//准备绘制内圆到外圆的直线，形成封闭区域
        currentPoint = baseRect.center() + ((currentPoint - baseRect.center()) * (2-m_innerOuterRate));//绘制内圆到外圆的直线，这里2-m_innerOuterRate其实是对应(1 + (1 -m_innerOuterRate))的
        dataPath.lineTo(currentPoint);
        p.setPen(Qt::NoPen);//这个很重要不然就会有绘制过程的一些轮廓了
    }

    p.setBrush(palette().highlight());
    p.setBrush(ringRunColor);

    p.drawPath(dataPath);
}

void QRoundProgressBar::calculateInnerRect(const QRectF &/*baseRect*/, double outerRadius, QRectF &innerRect, double &innerRadius)
{
    // for Line style
    if (m_barStyle == StyleLine) {
        innerRadius = outerRadius - m_outlinePenWidth;
    } else {
        innerRadius = outerRadius * m_outlinePenWidth;
    }

    double delta = (outerRadius - innerRadius) / 2;
    innerRect = QRectF(delta, delta, innerRadius, innerRadius);
//    innerRect = QRectF(227 - outerRadius, 220 - outerRadius, innerRadius * 2, innerRadius * 2);
}

void QRoundProgressBar::drawInnerBackground(QPainter &p, const QRectF &innerRect)
{
    if (m_barStyle == StyleDonut) {
        p.setBrush(palette().alternateBase());
        p.drawEllipse(innerRect);
    }
}

void QRoundProgressBar::drawText(QPainter &p, const QRectF &innerRect, double innerRadius, double value)
{
    if (m_format.isEmpty())
        return;

    // !!! to revise
    QFont f(font());
    f.setPixelSize(innerRadius * qMax(0.05, (0.35 - (double)m_decimals * 0.08)));
    p.setFont(f);

    QRectF textRect(innerRect);
    p.setPen(palette().text().color());
    p.drawText(textRect, Qt::AlignCenter, valueToText(value));
}

QString QRoundProgressBar::valueToText(double value) const
{
    QString textToDraw(m_format);

    if (m_updateFlags & UF_VALUE)
        textToDraw.replace("%v", QString::number(value, 'f', m_decimals));

    if (m_updateFlags & UF_PERCENT) {
        double procent = (value - m_min) / (m_max - m_min) * 100.0;
        textToDraw.replace("%p", QString::number(procent, 'f', m_decimals));
    }

    if (m_updateFlags & UF_MAX)
        textToDraw.replace("%m", QString::number(m_max - m_min + 1, 'f', m_decimals));
    return textToDraw;
}

void QRoundProgressBar::valueFormatChanged()
{
    m_updateFlags = 0;

    if (m_format.contains("%v"))
        m_updateFlags |= UF_VALUE;
    if (m_format.contains("%p"))
        m_updateFlags |= UF_PERCENT;
    if (m_format.contains("%m"))
        m_updateFlags |= UF_MAX;
    update();
}

void QRoundProgressBar::rebuildDataBrushIfNeeded()
{
    if (m_rebuildBrush) {
        m_rebuildBrush = false;
        QConicalGradient dataBrush;
        dataBrush.setCenter(0.5,0.5);
        dataBrush.setCoordinateMode(QGradient::StretchToDeviceMode);
        // invert colors
        for (int i = 0; i < m_gradientData.count(); i++) {
            dataBrush.setColorAt(1.0 - m_gradientData.at(i).first, m_gradientData.at(i).second);
        }
        // angle
        dataBrush.setAngle(m_nullPosition);
        QPalette p(palette());
        p.setBrush(QPalette::Window,Qt::NoBrush);
        p.setBrush(QPalette::AlternateBase,Qt::NoBrush);
        p.setBrush(QPalette::Highlight, dataBrush);
        setPalette(p);
    }
}

QColor QRoundProgressBar::getRingRunColor() const
{
    return ringRunColor;
}

void QRoundProgressBar::setRingRunColor(const QColor &value)
{
    ringRunColor = value;
}

void QRoundProgressBar::switchRunRingColor()
{
    ringRunColor = QColor(55, 144, 250,255);
    update();
}

void QRoundProgressBar::switchStopRingColor()
{
    ringRunColor = QColor(69, 173, 110,255);
    update();
}

/*
*监听主题
*/
void QRoundProgressBar::settingsStyle()
{

    GsettingSubject * subject = GsettingSubject::getInstance();;
    connect(subject,&GsettingSubject::blackStyle, this,[=](){
        mainColor = QColor(255, 255, 255, 40);
    });
    connect(subject,&GsettingSubject::whiteStyle, this,[=](){
         mainColor = QColor(255, 255, 255, 107);
    });
    subject->iniWidgetStyle();

}


